﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;

namespace JH
{
    public static class GetTypesByAttributeInGlobal
    {
        /// <summary>
        ///  缓存
        /// </summary>
        private static readonly Dictionary<Type, List<Type>> Cache = new Dictionary<Type, List<Type>>();

        /// <summary>
        /// 在全局环境中寻找标记了某个特性的类的类型
        /// </summary>
        public static List<Type> GetTypesByAttributeInGlobalEm(this Type attributeType,
            bool throwOnAssemblyLoadError = true)
        {
            // 如果传入的类型为空，抛出异常
            if (attributeType == null) throw new ArgumentNullException(nameof(attributeType));

            // 确保传入的类型是 Attribute 或其派生类的类型
            if (!typeof(Attribute).IsAssignableFrom(attributeType))
                throw new ArgumentException("传入的类型必须是 Attribute 或其派生类的类型。", nameof(attributeType));

            //如果缓存命中，直接返回
            if (Cache.TryGetValue(attributeType, out var cachedTypes))
                return cachedTypes;

            var typesWithAttribute = new List<Type>();

            // 遍历当前应用程序域中的所有程序集
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                try
                {
                    // 从程序集中获取所有类型，并找出标记了指定属性的类型
                    typesWithAttribute.AddRange(assembly.GetTypes()
                        .Where(type => type.GetCustomAttributes(attributeType, inherit: true).Any()));
                }
                catch (ReflectionTypeLoadException ex)
                {
                    if (!throwOnAssemblyLoadError) continue;

                    // 处理无法加载的类型
                    Debug.LogError($"无法加载程序集 {assembly.FullName} 中的某些类型: {ex.Message}");
                    throw;
                }
            }

            //加入缓存
            Cache[attributeType] = typesWithAttribute;
            
            // 返回标记了指定属性的所有类型
            return typesWithAttribute;
        }
    }
}